/*
 * Copyright (c) 2023 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <zephyr/random/random.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <bluetooth/mesh/vnd/le_pair_resp.h>
#include "../model_utils.h"
#include "mesh/net.h"

#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
#include "zephyr/logging/log.h"
LOG_MODULE_REGISTER(bt_mesh_le_pair_resp);

#define BT_MESH_LE_PAIR_OP BT_MESH_MODEL_OP_3(0x11, BT_MESH_VENDOR_COMPANY_ID_LE_PAIR_RESP)

#define BT_MESH_LE_PAIR_OP_RESET 0x00
#define BT_MESH_LE_PAIR_OP_STATUS 0x01

#define STATUS_PASSKEY_SET 0x00
#define STATUS_PASSKEY_NOT_SET 0x01

static uint32_t predefined_passkey = BT_PASSKEY_RAND;

static int handle_reset(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
			struct net_buf_simple *buf)
{
	uint32_t passkey;
	uint8_t status = STATUS_PASSKEY_SET;

	if (buf->len != 0) {
		return -EINVAL;
	}

	BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_LE_PAIR_OP, 5);

	if (predefined_passkey != BT_PASSKEY_RAND) {
		passkey = predefined_passkey;
	} else {
		passkey = sys_rand32_get() % 1000000;
		/* Overwrite the predefined passkey with the randomly generated passkey.
		 * LE pair responder can use the randomly generated passkey for the next
		 * pairing request.
		 */
		predefined_passkey = passkey;
	}

	bt_mesh_model_msg_init(&rsp, BT_MESH_LE_PAIR_OP);
	net_buf_simple_add_u8(&rsp, BT_MESH_LE_PAIR_OP_STATUS);
	net_buf_simple_add_u8(&rsp, status);
	if (status == STATUS_PASSKEY_SET) {
		net_buf_simple_add_le24(&rsp, passkey);
	}

	(void)bt_mesh_model_send(model, ctx, &rsp, NULL, NULL);

	return 0;
}

static int handle_op(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
		     struct net_buf_simple *buf)
{
	uint8_t op;

	op = net_buf_simple_pull_u8(buf);
	switch (op) {
	case BT_MESH_LE_PAIR_OP_RESET:
		return handle_reset(model, ctx, buf);
	default:
		LOG_WRN("Unknown opcode: %d", op);
	}

	return 0;
}

const struct bt_mesh_model_op _bt_mesh_le_pair_resp_op[] = {
	{ BT_MESH_LE_PAIR_OP, BT_MESH_LEN_MIN(1), handle_op, },
	BT_MESH_MODEL_OP_END,
};

static int bt_mesh_le_pair_resp_init(const struct bt_mesh_model *model)
{
	bt_mesh_le_pair_resp_passkey_invalidate();

	return 0;
}

static void bt_mesh_le_pair_resp_reset(const struct bt_mesh_model *model)
{
	int err;

	bt_mesh_le_pair_resp_passkey_invalidate();

	for (uint8_t id = 0; id < CONFIG_BT_ID_MAX; id++) {
		err = bt_unpair(id, NULL);
		if (err) {
			LOG_ERR("Unpair ID %u err: %d", id, err);
		}
	}
}

const struct bt_mesh_model_cb _bt_mesh_le_pair_resp_cb = {
	.init = bt_mesh_le_pair_resp_init,
	.reset = bt_mesh_le_pair_resp_reset,
};

void bt_mesh_le_pair_resp_passkey_invalidate(void)
{
	predefined_passkey = BT_PASSKEY_RAND;
}

void bt_mesh_le_pair_resp_passkey_set(uint32_t passkey)
{
	predefined_passkey = passkey;
}

uint32_t bt_mesh_le_pair_resp_passkey_get(void)
{
	return predefined_passkey;
}
